﻿#include "../inc/ff_utils.h"

namespace feifei
{
	static std::string gWorkspace = "";
	static std::string gDebugPath = "";
	static std::string gLogPath = "";
	LogFile* gLogFile = nullptr;

	void exec_cmd(std::string cmd)
	{
#ifdef _WIN32
		system(cmd.c_str());
#else
		FILE* pfp = popen(cmd.c_str(), "r");
		auto status = pclose(pfp);
		WEXITSTATUS(status);
#endif
	}

	std::string get_curr_path()
	{
#ifdef _WIN32
		char* buf = _getcwd(nullptr, 0);
#else
		char* buf = getcwd(nullptr, 0);
#endif
		std::string path(buf);
		free(buf);
		return path;
	}
	std::string get_work_path()
	{
		if(gWorkspace == "")
			set_work_path("");
		return gWorkspace;
	}
	std::string get_debug_path()
	{
		if (gWorkspace == "")
			set_work_path("");
		return gDebugPath;
	}
	std::string get_log_path()
	{
		if (gWorkspace == "")
			set_work_path("");
		return gLogPath;
	}
	E_ffState set_work_path(std::string path)
	{
		gWorkspace = (path == "") ? get_curr_path() : path;
		gWorkspace = gWorkspace + DIR_SPT;
		gDebugPath = gWorkspace + "debug" + DIR_SPT;
		gLogPath = gWorkspace + std::string("log") + DIR_SPT;
		if (ensure_path(gWorkspace.c_str()) != E_ffState::SUCCESS)
			ERR("failed to set workspace  : " + gWorkspace);
		if (ensure_path(gDebugPath.c_str()) != E_ffState::SUCCESS)
			ERR("failed to set debug path : " + gWorkspace);
		if(ensure_path(gLogPath.c_str()) != E_ffState::SUCCESS)
			ERR("failed to set log path   : " + gWorkspace);

		LOG("set workspace  : " + gWorkspace);
		LOG("set debug path : " + gDebugPath);
		LOG("set log path   : " + gLogPath);

		return E_ffState::SUCCESS;
	}
	void release_work_path()
	{
		gWorkspace = "";
		gDebugPath = "";
		gLogPath = "";
	}
	bool is_path_exist(std::string path)
	{
#ifdef _WIN32
		if (_access(path.c_str(), 2) == -1)
		{
			return false;
		}
#else
		if (access(path.c_str(), F_OK) == -1)
		{
			return false;
		}
#endif
		return true;
	}
	E_ffState ensure_path(std::string path)
	{
#ifdef _WIN32
		int rtn;
		rtn = _access(path.c_str(), 2);
		if (rtn == 0)
		{
			return E_ffState::SUCCESS;
		}
		else if (rtn == -1)
		{
			rtn = _mkdir(path.c_str());
			if (rtn != 0)
				return E_ffState::RTN_ERR;
		}
		else
		{
			return E_ffState::RTN_ERR;
		}
#else
		if (access(path.c_str(), F_OK) == -1)
		{
			::mkdir(path.c_str(), 0777);
		}
#endif
		return E_ffState::SUCCESS;
	}

	std::string get_file_path(std::string fileName)
	{
		size_t p;
		p = fileName.rfind(DIR_SPT);
		return fileName.substr(0, p);
	}
	std::string get_file_name(std::string fileName)
	{
		size_t p1, p2;
		p1 = fileName.rfind(DIR_SPT);
		p2 = fileName.rfind(".");
		return fileName.substr(p1 + 1, p2 - p1 - 1);
	}

#ifdef _WIN32
	std::string wstr_to_str(const std::wstring& wstr)
	{
		std::string strTo;
		char* szTo = new char[wstr.length() + 1];
		szTo[wstr.size()] = '\0';
		WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, szTo, (int)wstr.length(), NULL, NULL);
		strTo = szTo;
		delete[] szTo;
		return strTo;
	}
	std::wstring str_to_wstr(std::string str)
	{
		std::wstring result;
		//获取缓冲区大小，并申请空间，缓冲区大小按字符计算  
		int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), (int)(str.size()), NULL, 0);
		TCHAR* buffer = new TCHAR[len + 1];
		//多字节编码转换成宽字节编码  
		MultiByteToWideChar(CP_ACP, 0, str.c_str(), (int)(str.size()), buffer, len);
		buffer[len] = '\0';             //添加字符串结尾  
		//删除缓冲区并返回值  
		result.append(buffer);
		delete[] buffer;
		return result;
	}
#endif

	/************************************************************************/
	/* file and log															*/
	/************************************************************************/
	size_t read_bin_file(std::string file_name, char* binary)
	{
		std::ifstream fin(file_name.c_str(), std::ios::in | std::ios::binary);
		if (!fin.is_open())
		{
			WARN("can't open bin file: " + file_name);
			return 0;
		}

		size_t binSize;
		fin.seekg(0, std::ios::end);
		binSize = (size_t)fin.tellg();

		fin.seekg(0, std::ios::beg);
		fin.read(binary, binSize);

		fin.close();
		return binSize;
	}
	E_ffState write_to_bin_file(std::string file_name, std::vector<char>* binary)
	{
		std::ofstream fout(file_name.c_str(), std::ios::out | std::ios::binary);
		if (!fout.is_open())
		{
			ERR("can't open save file: " + file_name);
		}
		fout.write(binary->data(), binary->size());
		fout.close();
		return E_ffState::SUCCESS;
	}
	E_ffState write_to_txt_file(std::string file_name, std::string str)
	{
		std::ofstream fout(file_name.c_str(), std::ios::out | std::ios::ate);
		if (!fout.is_open())
		{
			ERR("can't open save file: " + file_name);
		}
		fout.write(str.c_str(), str.length());
		fout.close();
		return E_ffState::SUCCESS;
	}

#pragma region LOG

	std::string fmtTime(double sec)
	{
		char * p;
		if (sec >= 1.0)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.3f(sec)", sec);
			return std::string(p);
		}
		else if (sec >= 1e-3)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.3f(ms)", sec * 1000.0);
			return std::string(p);
		}
		else
		{
			p = (char*)alloca(128);
			sprintf(p, "%.3f(us)", sec * 1000.0 * 1000.0);
			return std::string(p);
		}
	}
	std::string fmtFreq(uint64_t freqHz)
	{
		char * p;
		if (freqHz >= 1000 * 1000 * 1000)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.1f(GHz)", freqHz / 1000.0 / 1000.0 / 1000.0);
			return std::string(p);
		}
		else if (freqHz >= 1000 * 1000)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.1f(MHz)", freqHz / 1000.0 / 1000.0);
			return std::string(p);
		}
		else if (freqHz >= 1000)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.1f(KHz)", freqHz / 1000.0);
			return std::string(p);
		}
		else
		{
			p = (char*)alloca(128);
			sprintf(p, "%lld(Hz)", freqHz);
			return std::string(p);
		}
	}
	std::string fmtSize(size_t szByte)
	{
		char * p;
		if (szByte >= (size_t)1024 * 1024 * 1024 * 1024)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.3f(TB)", szByte / 1024.0 / 1024.0 / 1024.0 / 1024.0);
			return std::string(p);
		}
		else if (szByte >= 1024 * 1024 * 1024)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.3f(GB)", szByte / 1024.0 / 1024.0 / 1024.0);
			return std::string(p);
		}
		else if (szByte >= 1024 * 1024)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.3f(MB)", szByte / 1024.0 / 1024.0);
			return std::string(p);
		}
		else if (szByte >= 1024)
		{
			p = (char*)alloca(128);
			sprintf(p, "%.3f(KB)", szByte / 1024.0);
			return std::string(p);
		}
		else
		{
			p = (char*)alloca(128);
			sprintf(p, "%zd(Byte)", szByte);
			return std::string(p);
		}
	}

	static const int PrintBufferSize = 1024;
	static char PrintBuffer[PrintBufferSize];

	static time_t t;
#ifdef _WIN32
	static struct tm stm;
#endif
	static std::string getCurrentTime()
	{
		memset(PrintBuffer, 0, PrintBufferSize);
		t = time(0);
#ifdef _WIN32
		localtime_s(&stm, &t);
		strftime(PrintBuffer, PrintBufferSize, "[%H:%M:%S]", &stm);
#else
		strftime(PrintBuffer, PrintBufferSize, "[%H:%M:%S]", localtime(&t));
#endif
		return std::string(PrintBuffer);
	}

	static const int CommentLength = 73;
	void PrintSeperator(const char c, FILE* of)
	{
		fprintf(of, "%s\n", std::string(CommentLength, c).c_str());
	}
	void PrintHeader(std::string header, const char c, FILE* of)
	{
		size_t hd_len = header.length();
		size_t blk_len;

		if (c != 0)
		{
			blk_len = (CommentLength - hd_len - 2) / 2;
			fprintf(of, "%c", c);
			fprintf(of, "%s", std::string(blk_len, ' ').c_str());
			fprintf(of, "%s", header.c_str());
			fprintf(of, "%s", std::string(CommentLength - hd_len - blk_len - 2, ' ').c_str());
			fprintf(of, "%c", c);
			fprintf(of, "\n");
		}
		else
		{
			blk_len = (CommentLength - hd_len) / 2;
			fprintf(of, "%s", std::string(blk_len, ' ').c_str());
			fprintf(of, "%s", header.c_str());
			fprintf(of, "%s", std::string(CommentLength - hd_len - blk_len, ' ').c_str());
			fprintf(of, "\n");
		}
	}

	void PrintInfo(const char * format, ...)
	{
		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
#ifdef _WIN32
		vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
#else
		vsprintf(PrintBuffer, format, args);
#endif
		printf("%s", PrintBuffer);
		va_end(args);
		printf("\n");
	}
	void PrintInfo(std::string msg, ...)
	{
		printf(msg.c_str());
		printf("\n");
	}

	void PrintLog(const char * format, ...)
	{
		std::clog << "[  LOG  ]" << getCurrentTime() << std::flush;

		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
#ifdef _WIN32
		vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
#else
		vsprintf(PrintBuffer, format, args);
#endif
		va_end(args);
		std::clog << std::string(PrintBuffer) << std::endl;
	}
	void PrintLog(std::string msg, ...)
	{
		std::clog << "[  LOG  ]" << getCurrentTime() << msg << std::endl;
	}

	void PrintWarning(const char *file, int line, const char * format, ...)
	{
		std::clog << "[WARNING]" << getCurrentTime() << std::flush;

		int pos;
		char * p = (char *)file;
		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
#ifdef _WIN32
		pos = vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
		p = strrchr(p, DIR_SPT) + 1;
		sprintf_s(PrintBuffer + pos, PrintBufferSize, " @%s:%d", p, line);
#else
		pos = vsprintf(PrintBuffer, format, args);
		p = strrchr(p, DIR_SPT) + 1;
		sprintf(PrintBuffer + pos, " @%s:%d", p, line);
#endif
		va_end(args);
		std::clog << std::string(PrintBuffer) << std::endl;
	}
	void PrintWarning(const char *file, int line, std::string msg, ...)
	{
		std::clog << "[WARNING]" << getCurrentTime() << msg << std::flush;

		std::string sf(file);
		std::clog << " @" << sf.erase(0, sf.find_last_of(DIR_SPT) + 1)
			<< ":" << line << std::endl;
	}

	E_ffState PrintError(const char *file, int line, const char * format, ...)
	{
		std::cerr << "[ERROR]" << getCurrentTime() << std::flush;

		int pos;
		char * p = (char *)file;
		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
#ifdef _WIN32
		pos = vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
		p = strrchr(p, DIR_SPT) + 1;
		sprintf_s(PrintBuffer + pos, PrintBufferSize, " @%s:%d", p, line);
#else
		pos = vsprintf(PrintBuffer, format, args);
		p = strrchr(p, DIR_SPT) + 1;
		sprintf(PrintBuffer + pos, " @%s:%d", p, line);
#endif
		va_end(args);
		std::cerr << std::string(PrintBuffer) << std::endl;

		return E_ffState::RTN_ERR;
	}
	E_ffState PrintError(const char *file, int line, std::string msg, ...)
	{
		std::cerr << "[ERROR]" << getCurrentTime() << msg << std::flush;

		std::string sf(file);

		std::cerr << " @" << sf.erase(0, sf.find_last_of(DIR_SPT) + 1)
			<< ":" << line << std::endl;

		return E_ffState::RTN_ERR;
	}

	void PrintFatal(const char *file, int line, const char * format, ...)
	{
		std::cerr << "[RTN_FATAL]" << getCurrentTime() << std::flush;

		int pos;
		char * p = (char *)file;
		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
#ifdef _WIN32
		pos = vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
		p = strrchr(p, DIR_SPT) + 1;
		sprintf_s(PrintBuffer + pos, PrintBufferSize, " @%s:%d", p, line);
#else
		pos = vsprintf(PrintBuffer, format, args);
		p = strrchr(p, DIR_SPT) + 1;
		sprintf(PrintBuffer + pos, " @%s:%d", p, line);
#endif
		va_end(args);
		std::cerr << std::string(PrintBuffer) << std::endl;

		exit(EXIT_FAILURE);
	}
	void PrintFatal(const char *file, int line, std::string msg, ...)
	{
		std::cerr << "[RTN_FATAL]" << getCurrentTime() << msg << std::flush;

		std::string sf(file);

		std::cerr << " @" << sf.erase(0, sf.find_last_of(DIR_SPT) + 1)
			<< ":" << line << std::endl;

		exit(EXIT_FAILURE);
	}

#define chkFStream() do{\
		if ((fstream == nullptr)||(!fstream->is_open())){\
			WARN("can't open log file");\
			fstream = nullptr;\
			return;\
		}}while(0)

	void LogFile::ensureLogDir()
	{
#ifdef _WIN32
		if (_access(log_dir.c_str(), 2) == -1)
		{
			_mkdir(log_dir.c_str());
		}
#else
		if (access(log_dir.c_str(), F_OK) == -1)
		{
			::mkdir(log_dir.c_str(), 0777);
		}
#endif
	}

	LogFile::LogFile(std::string file_name, bool isNew)
	{
		PrintBuffer = (char *)malloc(PrintBufferSize);

		if (gLogPath == "")
			log_dir = std::string(".") + DIR_SPT + "log" + DIR_SPT;
		else
			log_dir = gLogPath;
		ensureLogDir();

		if (file_name == "")
			this->file_name = log_dir;
		else
			this->file_name = log_dir + file_name + "_";

		if (isNew == true)
		{
			memset(PrintBuffer, 0, PrintBufferSize);
			t = time(0);
#ifdef _WIN32
			localtime_s(&stm, &t);
			strftime(PrintBuffer, PrintBufferSize, "%Y-%m-%d_%H-%M-%S", &stm);
#else
			strftime(PrintBuffer, PrintBufferSize, "%Y-%m-%d_%H-%M-%S", localtime(&t));
#endif
			this->file_name += std::string(PrintBuffer) + ".log";
			fstream = new std::ofstream(this->file_name, std::ios::out | std::ios::trunc);
		}
		else
		{
			this->file_name += ".log";
			fstream = new std::ofstream(this->file_name, std::ios::out | std::ios::app);
		}

		chkFStream();
	}
	LogFile::~LogFile()
	{
		free(PrintBuffer);
		if ((fstream != nullptr) && fstream->is_open())
		{
			fstream->close();
		}
		delete fstream;
	}

	void LogFile::Log(const char * format, ...)
	{
		chkFStream();

		*fstream << getCurrentTime() << std::flush;

		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
#ifdef _WIN32
		vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
#else
		vsprintf(PrintBuffer, format, args);
#endif
		va_end(args);
		*fstream << std::string(PrintBuffer) << std::endl;
	}
	void LogFile::Log(std::string msg, ...)
	{
		chkFStream();
		*fstream << getCurrentTime() << msg << std::endl;
	}
	void LogFile::Info(const char* format, ...)
	{
		chkFStream();

		*fstream << std::flush;

		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
#ifdef _WIN32
		vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
#else
		vsprintf(PrintBuffer, format, args);
#endif
		va_end(args);
		*fstream << std::string(PrintBuffer) << std::endl;
	}
	void LogFile::Info(std::string msg, ...)
	{
		chkFStream();
		*fstream << msg << std::endl;
	}

	void LogFile::PrintSeperator(const char c)
	{
		*fstream << std::string(CommentLength, c) << std::endl;
	}
	void LogFile::PrintHeader(std::string header, const char c)
	{
		size_t hd_len = header.length();
		size_t blk_len;

		if (c != 0)
		{
			blk_len = (CommentLength - hd_len - 2) / 2;
			*fstream << c;
			*fstream << std::string(blk_len, ' ');
			*fstream << header;
			*fstream << std::string(CommentLength - hd_len - blk_len - 2, ' ');
			*fstream << c;
			*fstream << std::endl;
		}
		else
		{
			blk_len = (CommentLength - hd_len) / 2;
			*fstream << std::string(blk_len, ' ');
			*fstream << header;
			*fstream << std::string(CommentLength - hd_len - blk_len, ' ');
			*fstream << std::endl;
		}
	}

	E_ffState CreateDefaultLogFile()
	{
		ReleaseDefaultLogFile();

		if (gLogPath == "")
		{
			return E_ffState::RTN_ERR;
		}
		else
		{
			if(ensure_path(gLogPath) == E_ffState::SUCCESS)
				gLogFile = new LogFile();
			else
				return E_ffState::RTN_ERR;
		}
		return E_ffState::SUCCESS;
	}
	void ReleaseDefaultLogFile()
	{
		if (gLogFile != nullptr)
		{
			delete gLogFile;
			gLogFile = nullptr;
		}
	}
	LogFile* GetDefaultLogFile()
	{
		return gLogFile;
	}
#pragma endregion

	/************************************************************************/
	/* timer																*/
	/************************************************************************/
#pragma region TIMER

#ifdef _WIN32
	void ffTimer::Restart()
	{
		QueryPerformanceFrequency(&cpuFreqHz);
		QueryPerformanceCounter(&startCnt);
	}

	void ffTimer::Stop()
	{
		QueryPerformanceCounter(&stopCnt);
		ElapsedMilliSec = (stopCnt.QuadPart - startCnt.QuadPart) * 1000.0 / cpuFreqHz.QuadPart;
	}
#else
	void ffTimer::Restart()
	{
		clock_gettime(CLOCK_MONOTONIC, &startTime);
	}

	void ffTimer::Stop()
	{
		clock_gettime(CLOCK_MONOTONIC, &stopTime);
		double d_startTime = static_cast<double>(startTime.tv_sec) * 1e9 + static_cast<double>(startTime.tv_nsec);
		double d_currentTime = static_cast<double>(stopTime.tv_sec) * 1e9 + static_cast<double>(stopTime.tv_nsec);
		ElapsedNanoSec = d_currentTime - d_startTime;
		ElapsedMilliSec = ElapsedNanoSec / 1e6;
	}

#endif

#pragma endregion

	/************************************************************************/
	/* command line parameter												*/
	/************************************************************************/
#pragma region CMD_IF

	CmdArgs* CmdArgs::pCmdArgs = nullptr;
	
	// not ready for now !
	CmdArgs::CmdArgs(int argc, char* argv[])
	{
		argsNum = 0;
		argsMap = new std::map<uint32_t, T_CmdArg*>();
		pCmdArgs = this;

		_argc = argc;
		_argv = argv;
	}
	CmdArgs::CmdArgs()
	{
		argsNum = 0;
		argsMap = new std::map<uint32_t, T_CmdArg*>();
		pCmdArgs = this;
	}
	CmdArgs* CmdArgs::GetCmdArgs()
	{
		if (pCmdArgs == nullptr)
			pCmdArgs = new CmdArgs();

		return pCmdArgs;
	}

	void* CmdArgs::GetOneArg(uint32_t id)
	{
		std::map<uint32_t, T_CmdArg*>::iterator it;
		it = argsMap->find(id);

		if (it == argsMap->end())
		{
			return nullptr;
		}

		return getOneArgValue(it->second);
	}

	void CmdArgs::AddOneArg(uint32_t id, E_ValueType dType, std::string defaultVal, char sName, std::string lName, std::string tHelp)
	{
		T_CmdArg* arg = new T_CmdArg;

		arg->id = id;
		arg->type = dType;
		arg->value = defaultVal;
		arg->shortName = sName;
		arg->longName = lName;
		arg->helpText = tHelp;
		setOneArgValue(arg, defaultVal);

		argsMap->insert(std::pair<uint32_t, T_CmdArg*>(id, arg));
		argsNum++;
	}

	// 解析所有命令行参数
	void CmdArgs::PaserCmdArgs(int argc, char* argv[])
	{
		if (argc == 0)
		{
			executePath = std::string(".") + DIR_SPT;
			return;
		}

		// use first arg to get current path
		size_t p;
		p = std::string(argv[0]).rfind(DIR_SPT);

		if (p == std::string::npos)
		{
			executePath = std::string(".") + DIR_SPT;
		}
		else
		{
			executePath = std::string(argv[0]).substr(0, p);
		}

		// other args
		for (int i = 1; i < argc; i++)
		{
			if ((std::string(argv[i]) == "--help") || (std::string(argv[i]) == "-h"))
			{
				helpText();
				exit(0);
			}
			else if ((argv[i][0] == '-') && (argv[i][1] == '-'))
			{
				if (i == argc - 1)
				{
					setOneArg(std::string(&argv[i][2]), nullptr);
				}
				else if (argv[i + 1][0] != '-')
				{
					setOneArg(std::string(&argv[i][2]), argv[i + 1]);
				}
			}
			else if (argv[i][0] == '-')
			{
				if (i == argc - 1)
				{
					setOneArg(argv[i][1], nullptr);
				}
				else if (argv[i + 1][0] != '-')
				{
					setOneArg(argv[i][1], argv[i + 1]);
				}
				else
				{
					setOneArg(argv[i][1], nullptr);
				}
			}
		}
	}
	void CmdArgs::helpText()
	{
		std::map<uint32_t, T_CmdArg*>::iterator it;

		for (it = argsMap->begin(); it != argsMap->end(); it++)
		{
			if (it->second->shortName != '\0')
				printf("-%c", it->second->shortName);
			else
				printf("  ");

			if (it->second->longName != "")
				printf(", --%s", it->second->longName.c_str());

			switch (it->second->type)
			{
			case E_ValueType::Int:printf("(%d)", it->second->iValue); break;
			case E_ValueType::Float:printf("(%.2f)", it->second->fValue); break;
			case E_ValueType::String:printf("(%s)", it->second->sValue.c_str()); break;
			default: break;
			}

			if (it->second->helpText != "")
				printf(": %s", it->second->helpText.c_str());

			printf("\n");
		}
	}
	// 根据命令行找到一个对应参数
	void CmdArgs::setOneArg(char sName, char* pvalue)
	{
		std::map<uint32_t, T_CmdArg*>::iterator it;

		for (it = argsMap->begin(); it != argsMap->end(); it++)
		{
			if (it->second->shortName == sName)
				break;
		}

		if (it == argsMap->end())
		{
			FATAL("no such param -%c.", sName);
		}

		return setOneArgValue(it->second, pvalue);
	}
	void CmdArgs::setOneArg(std::string lName, char* pvalue)
	{
		std::map<uint32_t, T_CmdArg*>::iterator it;

		for (it = argsMap->begin(); it != argsMap->end(); it++)
		{
			if (it->second->longName == lName)
				break;
		}

		if (it == argsMap->end())
		{
			FATAL("no such param --%s.", lName.c_str());
		}

		return setOneArgValue(it->second, pvalue);
	}

	// 根据命令行,设置/获取一个参数的值
	void CmdArgs::setOneArgValue(T_CmdArg* arg, char* pvalue)
	{
		if (pvalue == nullptr)
		{
			switch (arg->type)
			{
			case E_ValueType::Int:
				arg->iValue = 1;
				break;
			case E_ValueType::Float:
				arg->fValue = 0;
				break;
			case E_ValueType::String:
				arg->sValue = "";
				break;
			default:
				break;
			}
		}
		else
		{
			std::string value = std::string(pvalue);
			switch (arg->type)
			{
			case E_ValueType::Int:
				arg->iValue = atoi(value.c_str());
				break;
			case E_ValueType::Float:
				arg->fValue = atof(value.c_str());
				break;
			case E_ValueType::String:
				arg->sValue = value;
				break;
			default:
				break;
			}
		}
	}
	void CmdArgs::setOneArgValue(T_CmdArg* arg, std::string value)
	{
		switch (arg->type)
		{
		case E_ValueType::Int:
			arg->iValue = atoi(value.c_str());
			break;
		case E_ValueType::Float:
			arg->fValue = atof(value.c_str());
			break;
		case E_ValueType::String:
			arg->sValue = value;
			break;
		default:
			break;
		}
	}
	void* CmdArgs::getOneArgValue(T_CmdArg* arg)
	{
		switch (arg->type)
		{
		case E_ValueType::Int:		return &(arg->iValue);
		case E_ValueType::Float:		return &(arg->fValue);
		case E_ValueType::String:	return &(arg->sValue);
		default:					return nullptr;
		}
	}

#pragma endregion

	/************************************************************************/
	/* data base															*/
	/************************************************************************/
#pragma region DATA_BASE

	Database::Database(std::string db_name)
	{
		dbDirPath = get_work_path() + DIR_SPT + "db" + DIR_SPT;
		ensure_path(dbDirPath.c_str());
		dbFileName = db_name + ".db";

		std::string full_name = dbDirPath + dbFileName;
		std::ofstream fout(full_name.c_str(), std::ios::out | std::ios::binary | std::ios::app);
		fout.seekp(0, std::ios::end);

		size_t fSize = 0;
		fSize = (size_t)fout.tellp();
		if (fSize == 0)
			fout << "<db_file_start>" << std::endl;

		fout.close();
	}

	/* NEED TODO: 生成字符串键值 */
	std::string Database::GenKeyStr(T_SaveData sd)
	{
		char tmpc[1024];
		memset(tmpc, 0, 1024);
#ifdef _WIN32
		sprintf_s(tmpc, "A%d", sd.a);
#else
		sprintf(tmpc, "A%d", sd.a);
#endif
		return std::string(tmpc);
	}

	char Database::checkSum(std::string key, T_SaveData rcd)
	{
		char ck = '<';

		for (int i = 0; i < key.size(); i++)
			ck ^= key[i];
		ck ^= '>';

		char* prcd = (char*)(&rcd);
		for (int i = 0; i < sizeof(T_SaveData); i++)
			ck ^= prcd[i];

		return ck;
	}

	T_SaveData Database::Find(std::string key)
	{
		T_SaveData rcd;
		memset(&rcd, 0, sizeof(rcd));
		std::map<std::string, T_SaveData>::iterator it;
		it = SaveDataMap.find(key);

		if (it != SaveDataMap.end())
			rcd = it->second;

		return rcd;
	}
	void Database::AppendRcd(T_SaveData rcd)
	{
		std::string key = GenKeyStr(rcd);
		SaveDataMap.insert(std::pair<std::string, T_SaveData>(key, rcd));
	}

	void Database::SaveRcd(T_SaveData rcd)
	{
		std::string full_name = dbDirPath + dbFileName;
		std::ofstream fout(full_name.c_str(), std::ios::out | std::ios::binary | std::ios::app);
		fout.seekp(0, std::ios::end);

		std::string key = GenKeyStr(rcd);
		fout << '<';
		fout.write(key.c_str(), key.size());
		fout << '>';

		fout.write((char*)(&rcd), sizeof(T_SaveData));

		fout << '*';
		fout << checkSum(key, rcd);
		fout << '\n';

		fout.close();

		SaveDataMap.insert(std::pair<std::string, T_SaveData>(key, rcd));
	}
	void Database::ResaveDbFile()
	{
		std::string full_name = dbDirPath + dbFileName;
		std::ofstream fout(full_name.c_str(), std::ios::out | std::ios::binary);
		fout << "<db_file_start>" << std::endl;

		for (auto rcd : SaveDataMap)
		{
			SaveRcd(rcd.second);
		}
	}

	void Database::LoadDbFile()
	{
		std::string full_name = dbDirPath + dbFileName;
		std::ifstream fin(full_name.c_str(), std::ios::in | std::ios::binary);

		char tmp_key[1024];
		char a1 = 0, a2 = 0, a3 = 0;

		while (!fin.eof())
		{
			fin.get(a2);
			if (a2 == '<')
			{
				memset(tmp_key, 0, 1024);
				int idx = 0;

				fin.get(a2);
				while (a2 != '>')
				{
					tmp_key[idx++] = a2;
					fin.get(a2);
				}
				std::string key(tmp_key);

				if (key == "db_file_start")
					break;
			}
		}

		while (!fin.eof())
		{
			a1 = a2;
			fin.get(a2);
			if (a1 == '\n' && a2 == '<')
			{
				memset(tmp_key, 0, 1024);
				int idx = 0;

				fin.get(a2);
				while (a2 != '>')
				{
					tmp_key[idx++] = a2;
					fin.get(a2);
				}
				std::string key(tmp_key);

				T_SaveData rcd;
				char* prcd = (char*)&rcd;
				idx = 0;
				fin.get(a3); a1 = a2; a2 = a3;
				while (!fin.eof())
				{
					fin.get(a3);
					a1 = a2; a2 = a3;
					if ((a1 == '*' && a3 == '\n') || (idx == sizeof(T_SaveData)))
						break;

					prcd[idx++] = a1;
				}

				char chk1 = a2;
				char chk2 = checkSum(key, rcd);
				if (chk1 == chk2)
				{
					SaveDataMap.insert(std::pair<std::string, T_SaveData>(key, rcd));
				}
			}
		}
	}

#pragma endregion

	/************************************************************************/
	/* thread																*/
	/************************************************************************/
#pragma region MULT_THREAD
#ifdef _WIN32
	//https://www.hqfa65.top/index.php/tag/WIN%E5%A4%9A%E7%BA%BF%E7%A8%8B
#include <process.h> 

struct ThreadArgs
{
	void* entry_args;
	ThreadEntry entry_function;
};
unsigned __stdcall ThreadTrampoline(void* arg)
{
	ThreadArgs* thread_args = (ThreadArgs*)arg;
	ThreadEntry entry = thread_args->entry_function;
	void* data = thread_args->entry_args;
	delete thread_args;
	entry(data);
	_endthreadex(0);
	return 0;
}
Thread ThreadCreate(ThreadEntry entry_function, void* entry_argument, uint32_t stack_size)
{
	ThreadArgs* thread_args = new ThreadArgs();
	thread_args->entry_args = entry_argument;
	thread_args->entry_function = entry_function;
	uintptr_t ret = _beginthreadex(NULL, stack_size, ThreadTrampoline, thread_args, 0, NULL);
	return *(Thread*)&ret;
}
void ThreadDestory(Thread thread)
{ 
	CloseHandle(*(::HANDLE*)&thread); 
}
bool ThreadWaitFor(Thread thread)
{
	return WaitForSingleObject(*(::HANDLE*)&thread, INFINITE) == WAIT_OBJECT_0;
}
bool ThreadsWaitForAll(Thread* threads, uint32_t thread_count)
{
	return WaitForMultipleObjects(thread_count, (::HANDLE*)threads, TRUE, INFINITE) == WAIT_OBJECT_0;
}

Event EventCreate(bool auto_reset, bool init_state)
{
	Event evt = reinterpret_cast<Event>(CreateEvent(NULL, (BOOL)(!auto_reset), (BOOL)init_state, NULL));
	return evt;
}
void EventDestroy(Event event)
{
	CloseHandle(reinterpret_cast<::HANDLE>(event));
}
bool EventSet(Event event)
{
	return SetEvent(reinterpret_cast<::HANDLE>(event));
}
bool EventReset(Event event)
{
	return ResetEvent(reinterpret_cast<::HANDLE>(event));
}
bool EventWaitFor(Event event, int milli_seconds)
{
	if (event == NULL)
		return false;

	int ret_code = WaitForSingleObject(reinterpret_cast<::HANDLE>(event), milli_seconds);
	if (ret_code == WAIT_OBJECT_0)
		return true;
	else // WAIT_TIMEOUT or WAIT_FAILED
		return false;
}

Mutex MutexCreate() 
{ 
	return CreateEvent(NULL, false, true, NULL); 
}
void MutexDestroy(Mutex lock) 
{ 
	CloseHandle(*(::HANDLE*)&lock); 
}
bool MutexTryLock(Mutex lock)
{
	return WaitForSingleObject(*(::HANDLE*)&lock, 0) == WAIT_OBJECT_0;
}
bool MutexLock(Mutex lock)
{
	return WaitForSingleObject(*(::HANDLE*)&lock, INFINITE) == WAIT_OBJECT_0;
}
void MutexUnlock(Mutex lock) 
{
	SetEvent(*(::HANDLE*)&lock); 
}

Semaph SemaphCreate(uint32_t init_cnt, uint32_t max_cnt)
{
	return CreateSemaphore(NULL, init_cnt, max_cnt, NULL);
}
void SemaphDestroy(Semaph sam)
{
	CloseHandle(*(::HANDLE*)&sam);
}
bool SemaphPost(Semaph sam, long cnt, long *pre_cnt)
{
	return ReleaseSemaphore(*(::HANDLE*)&sam, cnt, pre_cnt);
}
bool SemaphPend(Semaph sam, int milli_seconds)
{
	int ret_code = WaitForSingleObject(reinterpret_cast<::HANDLE>(sam), milli_seconds);
	if (ret_code == WAIT_OBJECT_0)
		return true;
	else // WAIT_TIMEOUT or WAIT_FAILED
		return false;
}

#else
#include <pthread.h>
static struct timespec make_timeout(int milli_seconds)
{
	timespec tsp;
	struct timeval nowtime;
	gettimeofday(&nowtime,NULL);
	tsp.tv_sec = nowtime.tv_sec;
	tsp.tv_nsec = nowtime.tv_usec * 1000;
	unsigned int sec = milli_seconds / 1000;
	unsigned int msec = milli_seconds % 1000;
	unsigned int nsec = msec * 1000 * 1000;
	sec = sec + (tsp.tv_nsec + nsec) / (1000 * 1000 * 1000);

	tsp.tv_sec += sec;
	tsp.tv_nsec+= nsec;
	tsp.tv_nsec = tsp.tv_nsec % (1000 * 1000 * 1000);

	return tsp;
}
Thread ThreadCreate(ThreadEntry function, void* threadArgument, uint stackSize) 
{
	pthread_t tid = 0;
	int rtn = pthread_create(&tid, NULL, function, threadArgument);
	
	return (Thread)tid;
}
void ThreadDestory(Thread thread) 
{ 
	pthread_cancel((pthread_t)thread);
}
bool ThreadWaitFor(Thread thread) 
{ 
	pthread_join((pthread_t)thread, NULL);
	return true;
}
bool ThreadsWaitForAll(Thread* threads, uint threadCount) 
{
  for (uint i = 0; i < threadCount; i++) 
  	ThreadWaitFor(threads[i]);
  return true;
}

Event EventCreate(bool auto_reset, bool init_state) 
{
	pthread_cond_t * cond = (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
	pthread_cond_init(cond, NULL);
	if(init_state == true)
		pthread_cond_signal(cond);
	return (Event)cond;
}
void EventDestroy(Event event) 
{
	if(event == nullptr) return;
	pthread_cond_t * cond = (pthread_cond_t *)event;
	pthread_cond_destroy(cond);
  	free(cond);
}
bool EventWaitFor(Event event, int milli_seconds) 
{
	if(event == nullptr) return false;
	pthread_cond_t * cond = (pthread_cond_t *)event;
	pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
	int rtn = -1;
	pthread_mutex_lock(&mtx);

	if(milli_seconds == INFINITE)
	{
		rtn = pthread_cond_wait(cond, &mtx);
	}
	else
	{
		timespec tsp = make_timeout(milli_seconds);
		rtn = pthread_cond_timedwait(cond, &mtx, &tsp);
	}
	pthread_mutex_unlock(&mtx);
	pthread_mutex_destroy(&mtx);
	return rtn == 0;
}
bool EventSet(Event event) 
{
	if(event == nullptr) return false;
	pthread_cond_t * cond = (pthread_cond_t *)event;
	pthread_cond_signal(cond);
  	return true;
}
bool EventReset(Event event) 
{
	return true;
}

Mutex MutexCreate() 
{
  pthread_mutex_t * mtx = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
  pthread_mutex_init(mtx, NULL);
  return (Mutex)mtx;
}
void MutexDestroy(Mutex lock) 
{
  if(lock == nullptr) return;
  pthread_mutex_t * mtx = (pthread_mutex_t *)lock;
  pthread_mutex_destroy(mtx);
}
bool MutexTryLock(Mutex lock) 
{
  if(lock == nullptr) return false;
  pthread_mutex_t * mtx = (pthread_mutex_t *)lock;
  int rtn = pthread_mutex_trylock(mtx);
  free(mtx);
  return (rtn == 0);
}
bool MutexLock(Mutex lock) 
{
  if(lock == nullptr) return false;
  pthread_mutex_t * mtx = (pthread_mutex_t *)lock;
  int rtn = pthread_mutex_lock(mtx);
  return (rtn == 0);
}
void MutexUnlock(Mutex lock) 
{
  if(lock == nullptr) return;
  pthread_mutex_t * mtx = (pthread_mutex_t *)lock;
  pthread_mutex_unlock(mtx);
}

Semaph SemaphCreate(uint32_t init_cnt, uint32_t max_cnt)
{
	return (Semaph)nullptr;
}
void SemaphDestroy(Semaph sam)
{

}
bool SemaphPost(Semaph sam, long cnt, long* pre_cnt)
{
	return true;
}
bool SemaphPend(Semaph sam, int msec)
{
	return true;
}
#endif
#pragma endregion

}
